import copy
import json
import math

from sanweijiaXml.model import Machining, Line


# 刀具
class BitTool:
    # 刀具名称 宽度
    T129 = 10


# 计算各种孔位生成模型
class Algorithm:
    # 垂直孔
    @classmethod
    def vertical(cls, hole, is_back, var):
        match_model = Machining()
        match_model.Type = 2
        if is_back:
            match_model.Face = 6
            # 镜像翻转
            hole['XA'] = float(var['_BSX']) - float(hole['XA'])
        else:
            match_model.Z = hole['Height']
        match_model.X = hole['XA']
        match_model.Y = hole['YA']
        match_model.Diameter = hole['DU']
        match_model.Depth = hole['TI']
        return match_model

    # 水平孔
    @classmethod
    def horizontal(cls, hole):
        match_model = Machining()
        match_model.Type = 1
        match_model.X = hole['XA']
        match_model.Y = hole['YA']
        match_model.Depth = hole['TI']
        match_model.Diameter = hole['DU']
        if hole['BM'] == "XP":
            match_model.Face = 4
        elif hole['BM'] == "XM":
            match_model.Face = 3
        elif hole['BM'] == "YP":
            match_model.Face = 1
        elif hole['BM'] == "YM":
            match_model.Face = 2
        match_model.Z = hole['ZA']
        return match_model

    # 开槽 这个是大类，中间还会包括铣型 倒圆角 之类的
    @classmethod
    def groove(cls, hole, is_back, var):
        if cls.lineCoincidence(hole, var):
            return None
        match_model = Machining()
        if is_back:
            match_model.Face = 6
        start_position = Algorithm.getPosition(hole, var, 'EA')
        match_model.X = start_position['X']
        match_model.Y = start_position['Y']
        match_model.Width = eval("BitTool.T{}".format(hole['TNO']))
        match_model.ToolName = hole['TNO']
        match_model.Type = 3
        match_model.Depth = float(hole['Height']) - float(hole['ZA'])
        # if hole['RK'] != 'NOWRK':
        if cls.processingType(hole, var['MyExtend']):
            # 定义为内部框线
            match_model.wire_type = 2
            cls.millingType(match_model, hole, var['MyExtend'])
        else:
            # 定义为槽
            match_model.wire_type = 1
            cls.createGroove(match_model, hole, var)
        return match_model

    # 判断线条的数量。
    @classmethod
    def processingType(cls, hole, var):
        start = hole['EA'].split(':')
        end = hole['EE'].split(':')[1]
        line_key = start[0]
        start = start[1]
        ct = 0
        for key in var[line_key].keys():
            if int(key) > int(start):
                ct += 1
            if int(key) == int(end):
                break
        if ct > 1:
            return True

    # 创建一个槽
    @classmethod
    def createGroove(cls, match_model, hole, var):
        end_position = Algorithm.getPosition(hole, var, 'EE')
        line = Line()
        line.EndX = end_position['X']
        line.EndY = end_position['Y']
        match_model.lines.append(line)

    # 得到一个坐标
    @classmethod
    def getPosition(cls, hole, var, key):
        field = hole[key].split(':')
        new_var = var['MyExtend'][field[0]][field[1]]
        var = {'X': new_var['X'], 'Y': new_var['Y'], 'Z': new_var['Z']}
        if 'R' in new_var.keys():
            var['R'] = new_var['R']
        return var

    @classmethod
    def getAllPosition(cls, line: dict):
        positions = []
        for position in line.values():
            pos = [position['X'], position['Y']]
            positions.append(json.dumps(pos))
        return positions

    # 创建一个内部框
    @classmethod
    def millingType(cls, match_model, hole, var):
        match_model.EdgeABThickness = 1
        match_model.ToolName = "开料铣型刀"
        match_model.ToolOffset = "左"
        match_model.GrooveType = 1
        start = hole['EA'].split(':')
        end = hole['EE'].split(':')[1]
        line_key = start[0]
        start = start[1]
        line_id = 1
        previous_line = {'X': match_model.X, 'Y': match_model.Y}
        for key, line in var[line_key].items():
            if int(start) <= int(key) <= int(end):
                line_model = Line()
                line_model.LineID = line_id
                line_model.EndX = line["X"]
                line_model.EndY = line["Y"]
                if 'R' in line.keys():
                    angle = cls.getAngle(previous_line, line, line['R'])
                    if int(line['DS']) == 0:
                        line_model.Angle = -angle
                    else:
                        line_model.Angle = angle
                match_model.lines.append(line_model)
                previous_line = {'X': line['X'], 'Y': line['Y']}
                line_id += 1
            else:
                continue

    # 用来确定线条是否重合，方便最后加上开料刀
    @classmethod
    def lineCoincidence(cls, hole, hole_var):
        lines = hole_var['MyExtend']
        my_line = hole['EA'].split(':')[0]
        my_position = cls.getAllPosition(lines[my_line])
        for key, line in lines.items():
            if key == my_line:
                continue
            else:
                this_position = cls.getAllPosition(lines[key])
                if len(set(my_position) - set(this_position)) == 0:
                    return True
        return False

    # 添加线框
    @classmethod
    def addOutline(cls, hole_var: dict):
        outline = None
        outlines = []
        for lines in hole_var.values():
            if len(lines.values()) <= 0:
                continue
            lines_keys = list(lines.keys())
            line_first_post = lines[lines_keys[0]]
            line_last_post = lines[lines_keys[len(lines_keys) - 1]]
            if line_first_post['X'] == line_last_post['X'] and line_first_post['Y'] == line_last_post['Y']:
                outlines.append(lines)
        if len(outlines) > 0:
            if len(outlines) == 1:
                return cls.createOutline(outlines[0])
            else:
                return cls.createOutline(cls.getMaxEle(outlines))
        return outline

    @classmethod
    def getMaxEle(cls, outlines: list):
        line = outlines[0]
        for lines in outlines:
            private = cls.onTheFormula(line)
            this = cls.onTheFormula(lines)
            if this > private:
                line = lines
        return line

    # 计算坐标大小
    @classmethod
    def onTheFormula(cls, line):
        max_lines = sorted(list(line.values()), key=lambda x: (x['X'], x['Y']), reverse=True)
        max_max = max_lines[len(max_lines) - 1]
        max_min = max_lines[0]
        max_result = float(max_max['X']) + float(max_max['Y']) - float(max_min['X']) + float(max_min['Y'])
        return max_result

    # 创建外部线框，如果非异形返回空
    @classmethod
    def createOutline(cls, line_vars: dict):
        lines = list(line_vars.values())
        if len(lines) == 5:
            new_lines = copy.deepcopy(lines)
            del new_lines[0]
            for index in range(len(new_lines)):
                if float(new_lines[index]['X']) == 0 and float(new_lines[index]['Y']) == 0:
                    next_index, next_next_index, next_next_next_index = cls.getIndex(index, len(new_lines))
                    if new_lines[next_index]['X'] == new_lines[next_next_index]['X'] and new_lines[next_next_index][
                        'Y'] == \
                            new_lines[next_next_next_index]['Y']:
                        return None
        first_line = lines.pop(0)
        match = Machining()
        # 定义为外部框线
        match.wire_type = 3
        match.Type = 3
        match.Face = 5
        match.X = first_line['X']
        match.Y = first_line['Y']
        match.EdgeABThickness = 1
        match.ToolName = "开料铣型刀"
        match.ToolOffset = "右"
        loop = 1
        previous_line = {'X': first_line['X'], 'Y': first_line['Y']}
        for line in lines:
            line_model = Line()
            line_model.EndX = line['X']
            line_model.EndY = line['Y']
            line_model.LineID = loop
            if 'R' in line.keys():
                angle = cls.getAngle(previous_line, line, line['R'])
                line_model.Angle = -angle if int(line['DS']) == 0 else angle
            match.lines.append(line_model)
            previous_line = {'X': line['X'], 'Y': line['Y']}
            loop += 1
        return match

    @classmethod
    def getIndex(cls, index, max_index):
        next_index = index + 1
        next_next_index = next_index + 1
        next_next_next_index = next_next_index + 1
        if next_index >= max_index:
            next_index -= max_index
        if next_next_index >= max_index:
            next_next_index -= max_index
        if next_next_next_index >= max_index:
            next_next_next_index -= max_index
        return next_index, next_next_index, next_next_next_index

    @classmethod
    def getAngle(cls, start_point, end_point, radius):
        side_chief1 = abs(float(start_point['X']) - float(end_point['X']))
        side_chief2 = abs(float(start_point['Y']) - float(end_point['Y']))
        hypotenuse = math.sqrt(math.pow(side_chief1, 2) + math.pow(side_chief2, 2))
        trigonometric_radian = math.asin(hypotenuse / 2 / float(radius))
        radian = math.degrees(trigonometric_radian * 2)
        return round(radian, 3)
